using System;
using System.IO;
using Reflector.CodeModel;
using Reflector.CodeModel.Memory;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
namespace Reflector.CodeDom
{
    /// <summary>
    /// 
    /// </summary>
    internal sealed class VisitorWriter : Visitor
    {
        // Fields
        private readonly ILanguageWriterConfiguration configuration;
        private readonly IFormatter formatter;

        // Methods

        /// <summary>
        /// Initializes a new instance of the <see cref="VisitorWriter"/> class.
        /// </summary>
        /// <param name="formatter">The formatter.</param>
        /// <param name="configuration">The configuration.</param>
        public VisitorWriter(IFormatter formatter, ILanguageWriterConfiguration configuration)
        {
            this.formatter = formatter;
            this.configuration = configuration;
            codeStack = new System.Collections.Generic.Stack<CodeStackItem>();
        }
        /// <summary>
        /// Creates a safe name for a new variable of method being created.   Specifically, 
        /// will replace . with _ to result in a usable name.   Any additional replacements 
        /// should be added here
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        private string CreateSafeName(string name)
        {
            string returnvalue = name;
            returnvalue = returnvalue.Replace(".", "_");
            return returnvalue;
        }

        /// <summary>
        /// Visits a address dereference expression.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitAddressDereferenceExpression(IAddressDereferenceExpression value)
        {
            if (value != null)
            {
                WriteUnsupported(value);
            }
        }
        /// <summary>
        /// Visits a address of expression.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitAddressOfExpression(IAddressOfExpression value)
        {
            if (value != null)

                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits a address out expression.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitAddressOutExpression(IAddressOutExpression value)
        {
            if (value != null)

                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits a address reference expression.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitAddressReferenceExpression(IAddressReferenceExpression value)
        {
            if (value != null)

                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits a argument list expression.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitArgumentListExpression(IArgumentListExpression value)
        {
            if (value != null)

                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits a argument reference expression.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitArgumentReferenceExpression(IArgumentReferenceExpression value)
        {

            if (value != null)
            {
                formatter.Write(MethodTarget.BuildCodeString(
                    "new System.CodeDom.CodeArgumentReferenceExpression (\"" + value.Parameter.Name + "\")"));
                formatter.WriteLine();
            }
        }

        /// <summary>
        /// Visits a array create expression.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitArrayCreateExpression(IArrayCreateExpression value)
        {
            if (value != null)
            {
                WriteUnsupported(value);
            }
        }

        /// <summary>
        /// Visits a array indexer expression.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitArrayIndexerExpression(IArrayIndexerExpression value)
        {
            if (value != null)
            {
                WriteUnsupported(value);
            }
        }

        /// <summary>
        /// Visits a type of the array.
        /// </summary>
        /// <param name="type">a type.</param>
        public override void VisitArrayType(IArrayType type)
        {
            if (type != null)
            {
                WriteUnsupported(type);
            }
        }

        /// <summary>
        /// Visits a assembly.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitAssembly(IAssembly value)
        {
            if (value != null)
            {
                if (configuration["ShowNamespaceBody"] == "true")
                {
                }
                else
                {
                    formatter.Write("Visiting assembly: " + value.Name);
                }
            }
        }

        /// <summary>
        /// Visits a assign expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitAssignExpression(IAssignExpression value)
        {
            if (value != null)
            {
                string name = CreateSafeName("assign" + value.Target);
                formatter.Write("System.CodeDom.CodeAssignStatement " + name + " = new System.CodeDom.CodeAssignStatement();");
                formatter.WriteLine();
                formatter.Write(MethodTarget.BuildCodeString(name));
                formatter.WriteLine();

                codeStack.Push(new CodeStackItem(name, "Left", false));
                VisitExpression(value.Target);
                codeStack.Pop();
                codeStack.Push(new CodeStackItem(name, "Right", false));

                VisitExpression(value.Expression);
                codeStack.Pop();
            }
        }
        /// <summary>
        /// Visits a attach event statement.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitAttachEventStatement(IAttachEventStatement value)
        {
            if (value != null)

                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits a base reference expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitBaseReferenceExpression(IBaseReferenceExpression value)
        {
            if (value != null)

                WriteUnsupported(value);
        }


        /// <summary>
        /// Visits a binary expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitBinaryExpression(IBinaryExpression value)
        {
            if (value != null)
            {
                System.CodeDom.CodeBinaryOperatorExpression exp =
                    new System.CodeDom.CodeBinaryOperatorExpression();
                string name = "binaryExpression";// +value.ToString();
                formatter.Write("System.CodeDom.CodeBinaryOperatorExpression "
                    + name + " = new System.CodeDom.CodeBinaryOperatorExpression();");
                formatter.Write(MethodTarget.BuildCodeString(name));
                formatter.WriteLine();
                codeStack.Push(new CodeStackItem(name, "Left", false));
                VisitExpression(value.Left);
                codeStack.Pop();
                formatter.WriteLine();
                switch (value.Operator)
                {
                    case BinaryOperator.Add:
                        formatter.Write(name + ".Operator = System.CodeDom.CodeBinaryOperatorType.Add;");
                        break;
                    case BinaryOperator.Subtract:
                        formatter.Write(name + ".Operator = System.CodeDom.CodeBinaryOperatorType.Subtract;");
                        break;
                    case BinaryOperator.Divide:
                        formatter.Write(name + ".Operator = System.CodeDom.CodeBinaryOperatorType.Divide;");
                        break;
                    case BinaryOperator.Modulus:
                        formatter.Write(name + ".Operator = System.CodeDom.CodeBinaryOperatorType.Modulus;");
                        break;
                    case BinaryOperator.ShiftLeft:
                        formatter.WriteComment("// ShiftLeft operator not supported;");
                        break;
                    case BinaryOperator.ShiftRight:
                        formatter.WriteComment("// ShiftRight operator not supported");
                        break;
                    case BinaryOperator.IdentityEquality:
                        formatter.Write(name + ".Operator = System.CodeDom.CodeBinaryOperatorType.IdentityEquality;");
                        break;
                    case BinaryOperator.ValueEquality:
                        formatter.Write(name + ".Operator = System.CodeDom.CodeBinaryOperatorType.ValueEquality;");
                        break;
                    case BinaryOperator.IdentityInequality:
                        formatter.Write(name + ".Operator = System.CodeDom.CodeBinaryOperatorType.IdentityInequality;");
                        break;
                    case BinaryOperator.ValueInequality:
                        formatter.WriteComment("// Value inequality not supported.");
                        break;
                    case BinaryOperator.BitwiseOr:
                        formatter.Write(name + ".Operator = System.CodeDom.CodeBinaryOperatorType.BitwiseOr ;");
                        break;
                    case BinaryOperator.BitwiseAnd:
                        formatter.Write(name + ".Operator = System.CodeDom.CodeBinaryOperatorType.BitwiseAnd;");
                        break;
                    case BinaryOperator.BitwiseExclusiveOr:
                        formatter.WriteComment("// Bitwise exclusive or not supported;");
                        break;
                    case BinaryOperator.BooleanOr:
                        formatter.Write(name + ".Operator = System.CodeDom.CodeBinaryOperatorType.BitwiseOr;");
                        break;
                    case BinaryOperator.BooleanAnd:
                        formatter.Write(name + ".Operator = System.CodeDom.CodeBinaryOperatorType.BooleanAnd;");
                        break;
                    case BinaryOperator.LessThan:
                        formatter.Write(name + ".Operator = System.CodeDom.CodeBinaryOperatorType.LessThan;");
                        break;
                    case BinaryOperator.LessThanOrEqual:
                        formatter.Write(name + ".Operator = System.CodeDom.CodeBinaryOperatorType.LessThanOrEqual;");
                        break;
                    case BinaryOperator.GreaterThan:
                        formatter.Write(name + ".Operator = System.CodeDom.CodeBinaryOperatorType.GreaterThan;");
                        break;
                    case BinaryOperator.GreaterThanOrEqual:
                        formatter.Write(name + ".Operator = System.CodeDom.CodeBinaryOperatorType.GreaterThanOrEqual;");
                        break;
                }
                formatter.WriteLine();
                codeStack.Push(new CodeStackItem(name, "Right", false));
                VisitExpression(value.Right);
                codeStack.Pop();
                formatter.WriteLine();
            }
        }

        /// <summary>
        /// Visits a break statement.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitBreakStatement(IBreakStatement value)
        {

            if (value != null)
                formatter.WriteKeyword("break");
        }

        /// <summary>
        /// Visits a can cast expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitCanCastExpression(ICanCastExpression value)
        {
            if (value != null)
                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits a cast expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitCastExpression(ICastExpression value)
        {
            if (value != null)
                VisitExpression(value.Expression);
        }

        /// <summary>
        /// Visits a catch clause.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitCatchClause(ICatchClause value)
        {
            if (value != null)
            {
                VisitVariableDeclaration(value.Variable);
                VisitExpression(value.Condition);
                VisitStatement(value.Body);

            }
        }

        /// <summary>
        /// Visits a comment statement.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitCommentStatement(ICommentStatement value)
        {
            if (value != null)
                formatter.WriteLiteral("//" + value.Comment.Text);
        }

        /// <summary>
        /// Visits a condition case.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitConditionCase(IConditionCase value)
        {
            if (value != null)
            {
                VisitExpression(value.Condition);
                formatter.WriteLine();
                using (new IndentedCodeBlock(formatter))
                {
                    VisitBlockStatement(value.Body);
                }
            }
        }

        /// <summary>
        /// Visits a condition expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitConditionExpression(IConditionExpression value)
        {
            if (value != null)
            {
                formatter.Write("$(");
                formatter.WriteKeyword("if");
                //formatter.Write(" (");
                VisitExpression(value.Condition);
                formatter.Write(") { ");
                VisitExpression(value.Then);
                formatter.Write(" } ");
                if (value.Else != null)
                {
                    formatter.WriteKeyword("else");
                    formatter.Write(" { ");
                    VisitExpression(value.Else);
                    formatter.Write(" }");
                }
                formatter.Write(")");
            }
        }

        /// <summary>
        /// Visits a condition statement.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitConditionStatement(IConditionStatement value)
        {
            if (value != null)
            {
                string name = "condition";
                formatter.Write("System.CodeDom.CodeConditionStatement " + name
                    + " = new System.CodeDom.CodeConditionStatement(); ");
                //IndentedCodeBlock block;
                System.CodeDom.CodeConditionStatement cond
                    = new System.CodeDom.CodeConditionStatement();
                formatter.WriteLine();
                formatter.Write(MethodTarget.BuildCodeString(name));
                formatter.WriteLine();
                codeStack.Push(new CodeStackItem(name, "Condition", false));

                VisitExpression(value.Condition);
                codeStack.Pop();
                //formatter.Write(")");
                formatter.WriteLine();
                VisitStatement(value.Then);
                if (value.Else.Statements.Count != 0)
                {
                    formatter.WriteKeyword("else");
                    formatter.WriteLine();
                    //using (block = new IndentedCodeBlock(formatter))
                    {
                        VisitStatement(value.Else);
                    }
                }
            }
        }

        /// <summary>
        /// Visits a continue statement.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitContinueStatement(IContinueStatement value)
        {
            if (value != null)
                formatter.WriteKeyword("continue");
        }

        /// <summary>
        /// Visits a default case.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitDefaultCase(IDefaultCase value)
        {
            if (value != null)
            {
                formatter.WriteKeyword("default");
                formatter.WriteLine();
                using (new IndentedCodeBlock(formatter))
                {
                    VisitBlockStatement(value.Body);
                }
            }
        }

        /// <summary>
        /// Visits a delegate create expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitDelegateCreateExpression(IDelegateCreateExpression value)
        {
            if (value != null)
                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits a delegate invoke expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitDelegateInvokeExpression(IDelegateInvokeExpression value)
        {
            if (value != null)
                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits a do statement.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitDoStatement(IDoStatement value)
        {
            if (value != null)
            {
                WriteUnsupported(value);

            }
        }

        /// <summary>
        /// Visits a event reference.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitEventReference(IEventReference value)
        {
            if (value != null)
                WriteUnsupported(value.ToString());
        }

        /// <summary>
        /// Visits a event reference expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitEventReferenceExpression(IEventReferenceExpression value)
        {
            if (value != null)
                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits a expression collection.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitExpressionCollection(IExpressionCollection value)
        {
            if (value != null)
                VisitExpressionCollection(value, false);
        }

        /// <summary>
        /// Visits a expression collection.
        /// </summary>
        /// <param name="collection">a collection.</param>
        /// <param name="useColon">if set to <c>true</c> [use colon].</param>
        private void VisitExpressionCollection(IExpressionCollection collection, bool useColon)
        {

            foreach (IExpression expression in collection)
            {
                if (useColon && (collection.IndexOf(expression) != 0))
                {
                    formatter.Write(", ");
                }
                VisitExpression(expression);
            }
        }
        /// <summary>
        /// Visits a field declaration.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitFieldDeclaration(IFieldDeclaration value)
        {
            if (value != null)
            {
                string name = CreateSafeName("fieldDeclaration" + value.Name);
                VisitCustomAttributeCollection(value.Attributes);
                System.CodeDom.CodeMemberField fieldDeclaration = new System.CodeDom.CodeMemberField();
                fieldDeclaration.Name = value.Name;

                formatter.Write("System.CodeDom.CodeMemberField " + name + " = new System.CodeDom.CodeMemberField ();");
                formatter.WriteLine();
                formatter.Write(name + ".Name = \"" + value.Name + "\";");
                codeStack.Push(new CodeStackItem(name, "Type", false));
                formatter.WriteLine();

                //formatter.WriteComment(value.FieldType.GetType().ToString());
                formatter.Write(name + ".Type = new System.CodeDom.CodeTypeReference (\"" +
                    value.FieldType.ToString() + "\");");

                //VisitType(value.FieldType);
                codeStack.Pop();
            }
        }

        /// <summary>
        /// Visits a field reference.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitFieldReference(IFieldReference value)
        {
            if (value != null)

                formatter.Write(value.Name);
        }

        /// <summary>
        /// Visits a field reference expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitFieldReferenceExpression(IFieldReferenceExpression value)
        {
            if (value != null)
            {
                if (value.Field.Resolve().Static)
                {
                    formatter.Write("[");
                    VisitExpression(value.Target);
                    formatter.Write("]");
                    formatter.Write("::");
                    VisitFieldReference(value.Field);
                }
                else
                {
                    string name = CreateSafeName("fieldReference" + value.Field.Name);
                    formatter.Write("System.CodeDom.CodeFieldReferenceExpression " +
                        name + " = new System.CodeDom.CodeFieldReferenceExpression ();");
                    formatter.WriteLine();
                    formatter.Write(MethodTarget.BuildCodeString(name));
                    formatter.WriteLine();

                    formatter.Write(name + ".FieldName = \"" + value.Field.Name + "\";");
                    formatter.WriteLine();
                    codeStack.Push(new CodeStackItem(name, "TargetObject", false));
                    VisitExpression(value.Target);
                    codeStack.Pop();
                    formatter.WriteLine();
                }
            }
        }

        /// <summary>
        /// Visits for each statement.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitForEachStatement(IForEachStatement value)
        {
            if (value != null)
            {
                WriteUnsupported(value);
            }
        }

        /// <summary>
        /// Visits for statement.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitForStatement(IForStatement value)
        {
            if (value != null)
            {
                WriteUnsupported(value);
            }
        }
        /// <summary>
        /// Visits a lock statement.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitLockStatement(ILockStatement value)
        {
            if (value != null)
                base.VisitLockStatement(value);

        }
        /// <summary>
        /// Visits a anonymous method expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitAnonymousMethodExpression(IAnonymousMethodExpression value)
        {
            if (value != null)
                base.VisitAnonymousMethodExpression(value);
        }
        /// <summary>
        /// Visits a generic default expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitGenericDefaultExpression(IGenericDefaultExpression value)
        {
            if (value != null)

                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits a goto statement.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitGotoStatement(IGotoStatement value)
        {
            if (value != null)

                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits a labeled statement.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitLabeledStatement(ILabeledStatement value)
        {
            if (value != null)

                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits a literal expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitLiteralExpression(ILiteralExpression value)
        {
            if (value != null)
            {
                //name.Value = 
                string name = "literal" + value.Value.ToString();
                formatter.Write("System.CodeDom.CodePrimitiveExpression " + name +
                    " = new System.CodeDom.CodePrimitiveExpression();");
                formatter.WriteLine();
                if (value.Value is string)
                {
                    formatter.Write(name + ".Value = \"" + value.Value + "\";");
                }
                else if (value.Value is bool)
                {
                    formatter.Write(name + ".Value = " + (value.Value.ToString().ToLower()) + ";");
                }
                else if (value.Value == null)
                {
                    formatter.Write(name + ".Value = " + "null;");
                }
                else
                {
                    formatter.Write(MethodTarget.BuildCodeString(value.Value.ToString()) + ";");
                }
                formatter.WriteLine();
            }
        }

        /// <summary>
        /// Visits a method declaration.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitMethodDeclaration(IMethodDeclaration value)
        {
            if (value != null)
            {
                formatter.WriteKeyword("public System.CodeDom.CodeMemberMethod ");
                WriteWhitespace();
                formatter.WriteDeclaration("CreateMethod" + value.Name + "();");
                formatter.WriteLine();
                using (new IndentedCodeBlock(formatter))
                {
                    formatter.Write("System.CodeDom.CodeMemberMethod "
                        + value.Name
                        + " = new System.CodeDom.CodeMemberMethod();");
                    formatter.WriteLine();
                    formatter.Write(value.Name + ".Name = \"" + value.Name + "\";");
                    formatter.WriteLine();
                    formatter.Write(value.Name + ".ReturnType = new CodeTypeReference (typeof("
                        + value.ReturnType.Type.ToString() + "));");
                    formatter.WriteLine();
                    codeStack.Push(new CodeStackItem(value.Name,
                        "Parameters", true));
                    VisitParameterDeclarationCollection(value.Parameters);
                    codeStack.Pop();
                    codeStack.Push(new CodeStackItem(value.Name,
                        "Statements", true));
                    IBlockStatement body = value.Body as IBlockStatement;
                    if (body != null)
                    {
                        VisitBlockStatement(body);
                    }
                    codeStack.Pop();
                    formatter.Write("return " + value.Name + ";");
                    formatter.WriteLine();
                }
            }
        }

        /// <summary>
        /// Visits a method declaration collection.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitMethodDeclarationCollection(IMethodDeclarationCollection value)
        {
            if (value != null)
            {
                foreach (IMethodDeclaration declaration in value)
                {
                    VisitMethodDeclaration(declaration);
                    formatter.WriteLine();
                }
            }
        }


        /// <summary>
        /// Visits a method invoke expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitMethodInvokeExpression(IMethodInvokeExpression value)
        {
            if (value != null)
            {
                VisitExpression(value.Method);
                formatter.Write("(");
                foreach (IExpression expression in value.Arguments)
                {
                    if (value.Arguments.IndexOf(expression) != 0)
                    {
                        formatter.Write(", ");
                    }
                    VisitExpression(expression);
                }
                formatter.Write(")");
            }
        }
        /// <summary>
        /// Visits a method reference.
        /// </summary>
        /// <param name="value">a value.</param>
        /// <param name="processParameters">if set to <c>true</c> [process parameters].</param>
        public override void VisitMethodReference(IMethodReference value, bool processParameters)
        {
            if (value != null)
            {
                if (value.GenericArguments.Count > 0)
                {
                    MethodReferenceExpression expression = new MethodReferenceExpression();
                    expression.Method = value;
                    WriteUnsupported(expression);
                }
                else
                {
                    if (processParameters)
                    {
                        VisitParameterDeclarationCollection(value.Resolve().Parameters);
                        this.formatter.WriteReference(value.Name, formatter.ToString(), value);
                    }
                    IMethodDeclaration method = value.Resolve();

                    VisitBlockStatement(method.Body as IBlockStatement);
                }
            }
        }
        /// <summary>
        /// Visits a method reference expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitMethodReferenceExpression(IMethodReferenceExpression value)
        {
            if (value != null)
            {
                System.CodeDom.CodeMethodReferenceExpression methodReference =
                    new System.CodeDom.CodeMethodReferenceExpression();
                string name = CreateSafeName(value.Target.ToString());
                formatter.Write("System.CodeDom.CodeMethodReferenceExpression call"
                    + name + " = new System.CodeDom.CodeMethodReferenceExpression();");
                formatter.WriteLine();
                formatter.Write(MethodTarget.BuildCodeString("call" + name));
                formatter.WriteLine();
                if (value.Target is IBinaryExpression)
                {
                    formatter.Write("Target is a Binary Expression");
                    formatter.WriteLine();
                }
                else
                {
                    VisitExpression(value.Target);
                }
                VisitMethodReference(value.Method, false);
                codeStack.Push(new CodeStackItem("call" + name, "Parameters", true));
                VisitParameterReferenceCollection(value.Method.Parameters);
                codeStack.Pop();
            }
        }
        /// <summary>
        /// Visits a method return statement.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitMethodReturnStatement(IMethodReturnStatement value)
        {
            if (value != null)
            {
                System.CodeDom.CodeMethodReturnStatement returnStatement = new System.CodeDom.CodeMethodReturnStatement();
                formatter.Write("System.CodeDom.CodeMethodReturnStatement returnStatement = "
                    + " new System.CodeDom.CodeMethodReturnStatement ();");
                formatter.WriteLine();
                formatter.Write(MethodTarget.BuildCodeString("returnStatement"));
                formatter.WriteLine();
                codeStack.Push(new CodeStackItem("returnStatement", "Expression", false));
                VisitExpression(value.Expression);
                codeStack.Pop();
            }
        }

        /// <summary>
        /// Visits a type of a method return.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitMethodReturnType(IMethodReturnType value)
        {
        }

        /// <summary>
        /// Visits a module.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitModule(IModule value)
        {
            if (value != null)
            {
                if (configuration["ShowNamespaceBody"] == "true")
                {
                    base.VisitModule(value);
                }
                else
                {
                    formatter.Write("# Namespace ");
                    formatter.WriteDeclaration(value.Name);
                    formatter.WriteProperty("Location", value.Location);
                    long length = new FileInfo(Environment.ExpandEnvironmentVariables(value.Location)).Length;
                    if (length > 0xfa000L)
                    {
                        long num2 = length / 0xfa000L;
                        formatter.WriteProperty("Size", num2.ToString("F") + " Mb");
                    }
                    else if (length > 0x400L)
                    {
                        formatter.WriteProperty("Size", ((length / 0x400L)).ToString("F") + " Kb");
                    }
                    else
                    {
                        formatter.WriteProperty("Size", length + " Bytes");
                    }
                    formatter.WriteProperty("Runtime", value.TargetRuntimeVersion);
                }
            }
        }
        /// <summary>
        /// Visits a namespace.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitNamespace(INamespace value)
        {
            if (value != null)
            {
                if (configuration["ShowNamespaceBody"] == "true")
                {
                    base.VisitNamespace(value);
                }
                else
                {
                    formatter.Write("# Namespace ");
                    formatter.WriteDeclaration(value.Name);
                    formatter.WriteProperty("Assembly", Helper.GetAssemblyReference(value.Types[0]).ToString());
                    formatter.WriteProperty("Location", Helper.GetAssemblyReference(value.Types[0]).Resolve().Location);
                }
            }
        }
        /// <summary>
        /// Visits a null coalescing expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitNullCoalescingExpression(INullCoalescingExpression value)
        {
            if (value != null)
            {
                ConditionExpression expression = new ConditionExpression();
                BinaryExpression expression2 = new BinaryExpression();
                expression2.Left = value.Condition;
                expression2.Operator = BinaryOperator.ValueInequality;
                expression2.Right = new LiteralExpression();
                expression.Condition = expression2;
                expression.Then = value.Condition;
                expression.Else = value.Expression;
                VisitExpression(expression);
            }
        }
        /// <summary>
        /// Visits a object create expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitObjectCreateExpression(IObjectCreateExpression value)
        {
            if (value != null)
            {
                formatter.WriteKeyword("new-object");
                WriteWhitespace();
                VisitType(value.Constructor.DeclaringType);
                if (value.Arguments.Count > 0)
                {
                    formatter.Write("(");
                    VisitExpressionCollection(value.Arguments, true);
                    formatter.Write(")");
                }
            }
        }
        /// <summary>
        /// Visits a optional modifier.
        /// </summary>
        /// <param name="type">a type.</param>
        public override void VisitOptionalModifier(IOptionalModifier type)
        {
            if (type != null)

                WriteUnsupported(type.ToString());
        }
        /// <summary>
        /// Visits a parameter reference.
        /// </summary>
        /// <param name="value">a value.</param>
        public void VisitParameterReference(IParameterDeclaration value)
        {
            if (value != null)
            {

                formatter.Write(MethodTarget.BuildCodeString(
                    "new System.CodeDom.CodeParameterDeclarationExpression (\""
                    + value.ParameterType + "\",\"" + value.Name + "\")"));
                formatter.WriteLine();
            }
        }

        /// <summary>
        /// Visits a parameter declaration.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitParameterDeclaration(IParameterDeclaration value)
        {
            if (value != null)
            {
                formatter.Write(MethodTarget.BuildCodeString(
                    "new System.CodeDom.CodeParameterDeclarationExpression (\""
                    + value.ParameterType + "\",\"" + value.Name + "\")"));
                formatter.WriteLine();
            }
        }
        /// <summary>
        /// Visits a parameter declaration collection.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitParameterDeclarationCollection(IParameterDeclarationCollection value)
        {
            if (value != null)
            {
                if (value.Count > 0)
                {
                    foreach (IParameterDeclaration declaration in value)
                    {
                        VisitParameterDeclaration(declaration);
                    }
                }
            }
        }
        /// <summary>
        /// Visits a parameter reference collection.
        /// </summary>
        /// <param name="value">a value.</param>
        public void VisitParameterReferenceCollection(IParameterDeclarationCollection value)
        {
            if (value != null)
            {
                if (value.Count > 0)
                {
                    foreach (IParameterDeclaration declaration in value)
                    {
                        VisitParameterReference(declaration);
                    }
                }
            }
        }

        /// <summary>
        /// Visits a type of a pointer.
        /// </summary>
        /// <param name="type">a type.</param>
        public override void VisitPointerType(IPointerType type)
        {
            if (type != null)

                WriteUnsupported(type.ToString());
        }

        public override void VisitPropertyIndexerExpression(IPropertyIndexerExpression value)
        {
            if (value != null)
            {
                WriteUnsupported(value);
            }
        }
        /// <summary>
        /// Visits a property reference.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitPropertyReference(IPropertyReference value)
        {
            if (value != null)
            {
                formatter.Write(".");
                formatter.WriteReference(value.Name, value.Name, value);
            }
        }
        /// <summary>
        /// Visits a property reference expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitPropertyReferenceExpression(IPropertyReferenceExpression value)
        {
            if (value != null)
            {
                VisitExpression(value.Target);
                VisitPropertyReference(value.Property);
            }
        }

        /// <summary>
        /// Visits a property declaration.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitPropertyDeclaration(IPropertyDeclaration value)
        {
            formatter.WriteKeyword("public void");
            WriteWhitespace();
            formatter.WriteDeclaration("CreateProperty" + value.Name + "()");
            formatter.WriteLine();
            using (new IndentedCodeBlock(formatter))
            {
                System.CodeDom.CodeMemberProperty prop = new System.CodeDom.CodeMemberProperty();

                prop.Type = new System.CodeDom.CodeTypeReference(value.PropertyType.ToString());
                codeStack.Push(new CodeStackItem(value.Name, "Type", false));
                VisitType(value.PropertyType);
                codeStack.Pop();
                formatter.Write("System.CodeDom.CodeMemberProperty "
                    + value.Name
                    + " = new System.CodeDom.CodeMemberProperty();");
                formatter.WriteLine();
                formatter.Write(value.Name + ".Name = \"" + value.Name + "\";");
                formatter.WriteLine();
                if (value.GetMethod != null)
                {
                    codeStack.Push(new CodeStackItem(value.Name,
                        "GetStatements", true));
                    VisitMethodReference(value.GetMethod, false);
                    codeStack.Pop();
                }
                if (value.SetMethod != null)
                {
                    codeStack.Push(new CodeStackItem(value.Name,
                        "SetStatements", true));
                    VisitMethodReference(value.SetMethod, false);
                    codeStack.Pop();
                }
                formatter.WriteLine();
            }
        }

        /// <summary>
        /// Visits a type of a reference.
        /// </summary>
        /// <param name="type">a type.</param>
        public override void VisitReferenceType(IReferenceType type)
        {
            if (type != null)

                WriteUnsupported(type.ToString());
     
        }

        /// <summary>
        /// Visits a remove event statement.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitRemoveEventStatement(IRemoveEventStatement value)
        {
            if (value != null)

                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits a required modifier.
        /// </summary>
        /// <param name="type">a type.</param>
        public override void VisitRequiredModifier(IRequiredModifier type)
        {
            if (type != null)

                WriteUnsupported(type.ToString());
        }

        /// <summary>
        /// Visits a size of expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitSizeOfExpression(ISizeOfExpression value)
        {
            if (value != null)

                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits a snippet expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitSnippetExpression(ISnippetExpression value)
        {
            if (value != null)

                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits a stack allocate expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitStackAllocateExpression(IStackAllocateExpression value)
        {
            if (value != null)

                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits a statement collection.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitStatementCollection(IStatementCollection value)
        {
            if (value != null)
            {
                foreach (IStatement statement in value)
                {
                    //formatter.Write(value.ToString());
                    formatter.WriteLine();
                    VisitStatement(statement);
                    formatter.WriteLine();
                }
            }
        }
        /// <summary>
        /// Visits a switch statement.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitSwitchStatement(ISwitchStatement value)
        {
            if (value != null)
            {
                WriteUnsupported(value);
            }
        }
        /// <summary>
        /// Visits a this reference expression.
        /// </summary>
        /// <param name="value">a value.</param>
        public override void VisitThisReferenceExpression(IThisReferenceExpression value)
        {
            if (value != null)
            {

                formatter.Write(MethodTarget.BuildCodeString("new System.CodeDom.CodeThisReferenceExpression ()"));
                formatter.WriteLine();
            }
        }
        /// <summary>
        /// Visits the throw exception statement.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitThrowExceptionStatement(IThrowExceptionStatement value)
        {
            if (value != null)
            {
                string throwName = "throwStatement";

                formatter.Write("System.CodeDom.CodeThrowExceptionStatement " + throwName
                    + "= new System.CodeDom.CodeThrowExceptionStatement ();");
                formatter.WriteLine();
                System.CodeDom.CodeThrowExceptionStatement t = new System.CodeDom.CodeThrowExceptionStatement();
                codeStack.Push(new CodeStackItem(throwName, "ToThrow", false));
                VisitExpression(value.Expression);
                codeStack.Pop();
            }
        }
        /// <summary>
        /// Visits the try cast expression.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitTryCastExpression(ITryCastExpression value)
        {
            if (value != null)

                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits the try catch finally statement.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitTryCatchFinallyStatement(ITryCatchFinallyStatement value)
        {
            if (value != null)
            {

                string tryName = "trystatement";

                formatter.Write("System.CodeDom.CodeTryCatchFinallyStatement " + tryName + "= new System.CodeDom.CodeTryCatchFinallyStatement ();");
                formatter.WriteLine();
                formatter.Write(MethodTarget.BuildCodeString("trystatement"));
                formatter.WriteLine();

                codeStack.Push(new CodeStackItem(tryName, "TryStatements", true));
                VisitStatementCollection(value.Try.Statements as IStatementCollection);
                codeStack.Pop();
                codeStack.Push(new CodeStackItem(tryName, "CatchStatements", true));
                VisitCatchClauseCollection(value.CatchClauses);
                codeStack.Pop();
            }
        }

        /// <summary>
        /// Visits the type declaration.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitTypeDeclaration(ITypeDeclaration value)
        {
            if (value != null)
            {
                if (configuration["ShowTypeDeclarationBody"] == "true")
                {
                    base.VisitTypeDeclaration(value);
                }
                else
                {
                    formatter.Write("# Type ");
                    formatter.WriteDeclaration(value.Name);
                    formatter.WriteProperty("Name", value.Namespace + "." + value.Name);
                    formatter.WriteProperty("Assembly", Helper.GetAssemblyReference(value).ToString());
                    formatter.WriteProperty("Location", Helper.GetAssemblyReference(value).Resolve().Location);
                }
            }
        }
        /// <summary>
        /// Visits the typed reference create expression.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitTypedReferenceCreateExpression(ITypedReferenceCreateExpression value)
        {
            if (value != null)

                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits the type of expression.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitTypeOfExpression(ITypeOfExpression value)
        {
            if (value != null)
            {
                formatter.Write("(");
                formatter.WriteKeyword("typeof");
                formatter.Write(" ");
                VisitType(value.Type);
                formatter.Write(")");
            }
        }
        /// <summary>
        /// Visits the type of typed reference expression.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitTypeOfTypedReferenceExpression(ITypeOfTypedReferenceExpression value)
        {
            if (value != null)

                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits the type reference.
        /// </summary>
        /// <param name="type">The type.</param>
        public override void VisitTypeReference(ITypeReference type)
        {
            if (type != null)
            {
                base.VisitTypeReference(type);
                ITypeReference owner = type.Owner as ITypeReference;
                if (owner != null)
                {
                    VisitTypeReference(owner);
                }
                MethodTarget.BuildCodeString("new System.CodeDom.CodeTypeReference (\"" + type.Namespace + "." + type.Name + "\"");
            }
        }

        /// <summary>
        /// Visits the unary expression.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitUnaryExpression(IUnaryExpression value)
        {
            if (value != null)
                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits the using statement.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitUsingStatement(IUsingStatement value)
        {
            if (value != null)

                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits the value of typed reference expression.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitValueOfTypedReferenceExpression(IValueOfTypedReferenceExpression value)
        {
            if (value != null)

                WriteUnsupported(value);
        }

        /// <summary>
        /// Visits the variable declaration.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitVariableDeclaration(IVariableDeclaration value)
        {
            try
            {
                formatter.Write(MethodTarget.BuildCodeString(
                    " new CodeVariableDeclarationStatement ( \"" + value.VariableType
                    + "\",\"" + value.Name + "\")"));
                formatter.WriteLine();
            }
            catch
            {
                formatter.Write("Error buidling variable declaration logic");

            }
            formatter.WriteLine();
        }

        /// <summary>
        /// Visits the variable reference.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitVariableReference(IVariableReference value)
        {
            if (value != null)
            {

                formatter.Write(MethodTarget.BuildCodeString(
                    "new System.CodeDom.CodeVariableReferenceExpression (\"" + value.Resolve().Name + "\""));
            }
        }

        /// <summary>
        /// Visits the while statement.
        /// </summary>
        /// <param name="value">The value.</param>
        public override void VisitWhileStatement(IWhileStatement value)
        {
            if (value != null)

                WriteUnsupported(value);
        }
        /// <summary>
        /// Writes an unsupported comment.
        /// </summary>
        /// <param name="value">The value.</param>
        private void WriteUnsupported(IType value)
        {
            if (value != null)
            {
                formatter.WriteLiteral("// Unsupported expression "
                    + value.GetType().Name + ":");
                formatter.WriteLine();
                formatter.WriteLiteral("//" + value);
                formatter.WriteLine();
            }
        }

        /// <summary>
        /// Writes an unsupported comment.
        /// </summary>
        /// <param name="value">The value.</param>

        private void WriteUnsupported(IExpression value)
        {
            if (value != null)
            {
                formatter.WriteLiteral("// Unsupported expression "
                    + value.GetType().Name + ":");
                formatter.WriteLine();
                formatter.WriteLiteral("//" + value);
                formatter.WriteLine();
            }
        }

        /// <summary>
        /// Writes an unsupported comment.
        /// </summary>
        /// <param name="value">The value.</param>
        private void WriteUnsupported(IStatement value)
        {
            if (value != null)
            {
                formatter.WriteLiteral("// Unsupported statement " + value.GetType().Name + ":");
                formatter.WriteLine();
                formatter.WriteLiteral("//" + value);
                formatter.WriteLine();
            }
        }
        /// <summary>
        /// Writes an unsupported comment.
        /// </summary>
        /// <param name="value">The value.</param>
        private void WriteUnsupported(string value)
        {
            if (value != null)
            {
                formatter.WriteLiteral("// Unsupported expression:");
                formatter.WriteLine();
                formatter.WriteLiteral("//" + value);
                formatter.WriteLine();
            }
        }
        /// <summary>
        /// Writes  whitespace.
        /// </summary>
        private void WriteWhitespace()
        {

            formatter.Write(" ");
        }

        // Nested Types

        #region Nested type: IndentedCodeBlock

        /// <summary>
        /// 
        /// </summary>
        private class IndentedCodeBlock : IDisposable
        {
            private readonly IFormatter formatter;

            /// <summary>
            /// Adds a level of idention to the outputted code
            /// </summary>
            /// <param name="formatter">The formatter.</param>
            public IndentedCodeBlock(IFormatter formatter)
            {
                this.formatter = formatter;
                formatter.Write("{");
                formatter.WriteLine();
                formatter.WriteIndent();
            }

            #region IDisposable Members

            /// <summary>
            /// Removed the level of indention created in the constructor
            /// </summary>
            public void Dispose()
            {
                formatter.WriteOutdent();
                formatter.Write("}");
                formatter.WriteLine();
            }

            #endregion
        }

        #endregion
    }
}